{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configurations for Colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = \"google.colab\" in sys.modules\n",
    "\n",
    "if IN_COLAB:\n",
    "    !apt install python-opengl\n",
    "    !apt install ffmpeg\n",
    "    !apt install xvfb\n",
    "    !pip install PyVirtualDisplay==3.0\n",
    "    !pip install gymnasium==0.28.1\n",
    "    from pyvirtualdisplay import Display\n",
    "    \n",
    "    # Start virtual display\n",
    "    dis = Display(visible=0, size=(400, 400))\n",
    "    dis.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 07. N-Step Learning\n",
    "\n",
    "[R. S. Sutton, \"Learning to predict by the methods of temporal differences.\" Machine learning, 3(1):9–44, 1988.](http://incompleteideas.net/papers/sutton-88-with-erratum.pdf)\n",
    "\n",
    "Q-learning accumulates a single reward and then uses the greedy action at the next step to bootstrap. Alternatively, forward-view multi-step targets can be used (Sutton 1988). We call it Truncated N-Step Return\n",
    "from a given state $S_t$. It is defined as,\n",
    "\n",
    "$$\n",
    "R^{(n)}_t = \\sum_{k=0}^{n-1} \\gamma_t^{(k)} R_{t+k+1}.\n",
    "$$\n",
    "\n",
    "A multi-step variant of DQN is then defined by minimizing the alternative loss,\n",
    "\n",
    "$$\n",
    "(R^{(n)}_t + \\gamma^{(n)}_t \\max_{a'} q_{\\theta}^{-}\n",
    "(S_{t+n}, a')\n",
    "- q_{\\theta}(S_t, A_t))^2.\n",
    "$$\n",
    "\n",
    "Multi-step targets with suitably tuned $n$ often lead to faster learning (Sutton and Barto 1998)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/jinwoo.park/miniforge3/envs/rainbow-is-all-you-need/lib/python3.8/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "from collections import deque\n",
    "from typing import Deque, Dict, List, Tuple\n",
    "\n",
    "import gymnasium as gym\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "from IPython.display import clear_output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Replay buffer for N-step learning\n",
    "\n",
    "There are a little bit changes in Replay buffer for N-step learning. First, we use `deque` to store the most recent n-step transitions.\n",
    "\n",
    "```python\n",
    "    self.n_step_buffer = deque(maxlen=n_step)\n",
    "```\n",
    "\n",
    "You can see it doesn't actually store a transition in the buffer, unless `n_step_buffer` is full.\n",
    "\n",
    "```\n",
    "    # in store method\n",
    "    if len(self.n_step_buffer) < self.n_step:\n",
    "        return ()\n",
    "```\n",
    "\n",
    "When the length of `n_step_buffer` becomes equal to N, it eventually stores the N-step transition, which is calculated by `_get_n_step_info` method.\n",
    "\n",
    "(Please see *01.dqn.ipynb* for detailed description of the basic replay buffer.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReplayBuffer:\n",
    "    \"\"\"A simple numpy replay buffer.\"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        obs_dim: int, \n",
    "        size: int, \n",
    "        batch_size: int = 32, \n",
    "        n_step: int = 3, \n",
    "        gamma: float = 0.99,\n",
    "    ):\n",
    "        self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.acts_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.rews_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.done_buf = np.zeros(size, dtype=np.float32)\n",
    "        self.max_size, self.batch_size = size, batch_size\n",
    "        self.ptr, self.size, = 0, 0\n",
    "        \n",
    "        # for N-step Learning\n",
    "        self.n_step_buffer = deque(maxlen=n_step)\n",
    "        self.n_step = n_step\n",
    "        self.gamma = gamma\n",
    "\n",
    "    def store(\n",
    "        self, \n",
    "        obs: np.ndarray, \n",
    "        act: np.ndarray, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool\n",
    "    ) -> Tuple[np.ndarray, np.ndarray, float, np.ndarray, bool]:\n",
    "        transition = (obs, act, rew, next_obs, done)\n",
    "        self.n_step_buffer.append(transition)\n",
    "\n",
    "        # single step transition is not ready\n",
    "        if len(self.n_step_buffer) < self.n_step:\n",
    "            return ()\n",
    "        \n",
    "        # make a n-step transition\n",
    "        rew, next_obs, done = self._get_n_step_info(\n",
    "            self.n_step_buffer, self.gamma\n",
    "        )\n",
    "        obs, act = self.n_step_buffer[0][:2]\n",
    "        \n",
    "        self.obs_buf[self.ptr] = obs\n",
    "        self.next_obs_buf[self.ptr] = next_obs\n",
    "        self.acts_buf[self.ptr] = act\n",
    "        self.rews_buf[self.ptr] = rew\n",
    "        self.done_buf[self.ptr] = done\n",
    "        self.ptr = (self.ptr + 1) % self.max_size\n",
    "        self.size = min(self.size + 1, self.max_size)\n",
    "        \n",
    "        return self.n_step_buffer[0]\n",
    "\n",
    "    def sample_batch(self) -> Dict[str, np.ndarray]:\n",
    "        indices = np.random.choice(\n",
    "            self.size, size=self.batch_size, replace=False\n",
    "        )\n",
    "\n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "            # for N-step Learning\n",
    "            indices=indices,\n",
    "        )\n",
    "    \n",
    "    def sample_batch_from_idxs(\n",
    "        self, indices: np.ndarray\n",
    "    ) -> Dict[str, np.ndarray]:\n",
    "        # for N-step Learning\n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "        )\n",
    "    \n",
    "    def _get_n_step_info(\n",
    "        self, n_step_buffer: Deque, gamma: float\n",
    "    ) -> Tuple[np.int64, np.ndarray, bool]:\n",
    "        \"\"\"Return n step rew, next_obs, and done.\"\"\"\n",
    "        # info of the last transition\n",
    "        rew, next_obs, done = n_step_buffer[-1][-3:]\n",
    "\n",
    "        for transition in reversed(list(n_step_buffer)[:-1]):\n",
    "            r, n_o, d = transition[-3:]\n",
    "\n",
    "            rew = r + gamma * rew * (1 - d)\n",
    "            next_obs, done = (n_o, d) if d else (next_obs, done)\n",
    "\n",
    "        return rew, next_obs, done\n",
    "\n",
    "    def __len__(self) -> int:\n",
    "        return self.size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network\n",
    "\n",
    "We are going to use a simple network architecture with three fully connected layers and two non-linearity functions (ReLU)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Network(nn.Module):\n",
    "    def __init__(self, in_dim: int, out_dim: int):\n",
    "        \"\"\"Initialization.\"\"\"\n",
    "        super(Network, self).__init__()\n",
    "\n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, 128), \n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 128), \n",
    "            nn.ReLU(), \n",
    "            nn.Linear(128, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, x: torch.Tensor) -> torch.Tensor:\n",
    "        \"\"\"Forward method implementation.\"\"\"\n",
    "        return self.layers(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DQN Agent + N-step learning Agent\n",
    "\n",
    "Here is a summary of DQNAgent class.\n",
    "\n",
    "| Method           | Note                                                 |\n",
    "| ---              | ---                                                  |\n",
    "|select_action     | select an action from the input state.               |\n",
    "|step              | take an action and return the response of the env.   |\n",
    "|compute_dqn_loss  | return dqn loss.                                     |\n",
    "|update_model      | update the model by gradient descent.                |\n",
    "|target_hard_update| hard update from the local model to the target model.|\n",
    "|train             | train the agent during num_frames.                   |\n",
    "|test              | test the agent (1 episode).                          |\n",
    "|plot              | plot the training progresses.                        |\n",
    "\n",
    "We use two buffers: `memory` and `memory_n` for 1-step transitions and n-step transitions respectively. It guarantees that any paired 1-step and n-step transitions have the same indices (See `step` method for more details). Due to the reason, we can sample pairs of transitions from the two buffers once we have indices for samples.\n",
    "\n",
    "```python\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        ...\n",
    "        samples = self.memory.sample_batch()\n",
    "        indices = samples[\"indices\"]\n",
    "        ...\n",
    "        \n",
    "        # N-step Learning loss\n",
    "        if self.use_n_step:\n",
    "            samples = self.memory_n.sample_batch_from_idxs(indices)\n",
    "            ...\n",
    "```\n",
    "\n",
    "One thing to note that  we are gonna combine 1-step loss and n-step loss so as to control high-variance / high-bias trade-off.\n",
    "\n",
    "(Search the comments with *N-step Leaning* to see any difference from DQN.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DQNAgent:\n",
    "    \"\"\"DQN Agent interacting with environment.\n",
    "    \n",
    "    Attribute:\n",
    "        env (gym.Env): openAI Gym environment\n",
    "        memory (ReplayBuffer): replay memory to store transitions\n",
    "        batch_size (int): batch size for sampling\n",
    "        epsilon (float): parameter for epsilon greedy policy\n",
    "        epsilon_decay (float): step size to decrease epsilon\n",
    "        max_epsilon (float): max value of epsilon\n",
    "        min_epsilon (float): min value of epsilon\n",
    "        target_update (int): period for target model's hard update\n",
    "        gamma (float): discount factor\n",
    "        dqn (Network): model to train and select actions\n",
    "        dqn_target (Network): target model to update\n",
    "        optimizer (torch.optim): optimizer for training dqn\n",
    "        transition (list): transition information including \n",
    "                           state, action, reward, next_state, done\n",
    "        use_n_step (bool): whether to use n_step memory\n",
    "        n_step (int): step number to calculate n-step td error\n",
    "        memory_n (ReplayBuffer): n-step replay buffer\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        env: gym.Env,\n",
    "        memory_size: int,\n",
    "        batch_size: int,\n",
    "        target_update: int,\n",
    "        epsilon_decay: float,\n",
    "        seed: int,\n",
    "        max_epsilon: float = 1.0,\n",
    "        min_epsilon: float = 0.1,\n",
    "        gamma: float = 0.99,\n",
    "        # N-step Learning\n",
    "        n_step: int = 3,\n",
    "    ):\n",
    "        \"\"\"Initialization.\n",
    "        \n",
    "        Args:\n",
    "            env (gym.Env): openAI Gym environment\n",
    "            memory_size (int): length of memory\n",
    "            batch_size (int): batch size for sampling\n",
    "            target_update (int): period for target model's hard update\n",
    "            epsilon_decay (float): step size to decrease epsilon\n",
    "            lr (float): learning rate\n",
    "            max_epsilon (float): max value of epsilon\n",
    "            min_epsilon (float): min value of epsilon\n",
    "            gamma (float): discount factor\n",
    "            n_step (int): step number to calculate n-step td error\n",
    "        \"\"\"\n",
    "        obs_dim = env.observation_space.shape[0]\n",
    "        action_dim = env.action_space.n\n",
    "        \n",
    "        self.env = env\n",
    "        self.batch_size = batch_size\n",
    "        self.epsilon = max_epsilon\n",
    "        self.epsilon_decay = epsilon_decay\n",
    "        self.seed = seed\n",
    "        self.max_epsilon = max_epsilon\n",
    "        self.min_epsilon = min_epsilon\n",
    "        self.target_update = target_update\n",
    "        self.gamma = gamma\n",
    "        \n",
    "        # memory for 1-step Learning\n",
    "        self.memory = ReplayBuffer(\n",
    "            obs_dim, memory_size, batch_size, n_step=1, gamma=gamma\n",
    "        )\n",
    "        \n",
    "        # memory for N-step Learning\n",
    "        self.use_n_step = True if n_step > 1 else False\n",
    "        if self.use_n_step:\n",
    "            self.n_step = n_step\n",
    "            self.memory_n = ReplayBuffer(\n",
    "                obs_dim, memory_size, batch_size, n_step=n_step, gamma=gamma\n",
    "            )\n",
    "        \n",
    "        # device: cpu / gpu\n",
    "        self.device = torch.device(\n",
    "            \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "        )\n",
    "        print(self.device)\n",
    "\n",
    "        # networks: dqn, dqn_target\n",
    "        self.dqn = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "        self.dqn_target.eval()\n",
    "        \n",
    "        # optimizer\n",
    "        self.optimizer = optim.Adam(self.dqn.parameters())\n",
    "\n",
    "        # transition to store in memory\n",
    "        self.transition = list()\n",
    "        \n",
    "        # mode: train / test\n",
    "        self.is_test = False\n",
    "\n",
    "    def select_action(self, state: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Select an action from the input state.\"\"\"\n",
    "        # epsilon greedy policy\n",
    "        if self.epsilon > np.random.random():\n",
    "            selected_action = self.env.action_space.sample()\n",
    "        else:\n",
    "            selected_action = self.dqn(\n",
    "                torch.FloatTensor(state).to(self.device)\n",
    "            ).argmax()\n",
    "            selected_action = selected_action.detach().cpu().numpy()\n",
    "        \n",
    "        if not self.is_test:\n",
    "            self.transition = [state, selected_action]\n",
    "        \n",
    "        return selected_action\n",
    "\n",
    "    def step(self, action: np.ndarray) -> Tuple[np.ndarray, np.float64, bool]:\n",
    "        \"\"\"Take an action and return the response of the env.\"\"\"\n",
    "        next_state, reward, terminated, truncated, _ = self.env.step(action)\n",
    "        done = terminated or truncated\n",
    "        \n",
    "        if not self.is_test:\n",
    "            self.transition += [reward, next_state, done]\n",
    "            \n",
    "            # N-step transition\n",
    "            if self.use_n_step:\n",
    "                one_step_transition = self.memory_n.store(*self.transition)\n",
    "            # 1-step transition\n",
    "            else:\n",
    "                one_step_transition = self.transition\n",
    "\n",
    "            # add a single step transition\n",
    "            if one_step_transition:\n",
    "                self.memory.store(*one_step_transition)\n",
    "    \n",
    "        return next_state, reward, done\n",
    "\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        \"\"\"Update the model by gradient descent.\"\"\"\n",
    "        samples = self.memory.sample_batch()\n",
    "        indices = samples[\"indices\"]\n",
    "        loss = self._compute_dqn_loss(samples, self.gamma)\n",
    "        \n",
    "        # N-step Learning loss\n",
    "        # we are gonna combine 1-step loss and n-step loss so as to\n",
    "        # prevent high-variance.\n",
    "        if self.use_n_step:\n",
    "            samples = self.memory_n.sample_batch_from_idxs(indices)\n",
    "            gamma = self.gamma ** self.n_step\n",
    "            n_loss = self._compute_dqn_loss(samples, gamma)\n",
    "            loss += n_loss\n",
    "\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "\n",
    "        return loss.item()\n",
    "        \n",
    "    def train(self, num_frames: int, plotting_interval: int = 200):\n",
    "        \"\"\"Train the agent.\"\"\"\n",
    "        self.is_test = False\n",
    "        \n",
    "        state, _ = self.env.reset(seed=self.seed)\n",
    "        update_cnt = 0\n",
    "        epsilons = []\n",
    "        losses = []\n",
    "        scores = []\n",
    "        score = 0\n",
    "\n",
    "        for frame_idx in range(1, num_frames + 1):\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "\n",
    "            # if episode ends\n",
    "            if done:\n",
    "                state, _ = self.env.reset(seed=self.seed)\n",
    "                scores.append(score)\n",
    "                score = 0\n",
    "\n",
    "            # if training is ready\n",
    "            if len(self.memory) >= self.batch_size:\n",
    "                loss = self.update_model()\n",
    "                losses.append(loss)\n",
    "                update_cnt += 1\n",
    "                \n",
    "                # linearly decrease epsilon\n",
    "                self.epsilon = max(\n",
    "                    self.min_epsilon, self.epsilon - (\n",
    "                        self.max_epsilon - self.min_epsilon\n",
    "                    ) * self.epsilon_decay\n",
    "                )\n",
    "                epsilons.append(self.epsilon)\n",
    "                \n",
    "                # if hard update is needed\n",
    "                if update_cnt % self.target_update == 0:\n",
    "                    self._target_hard_update()\n",
    "\n",
    "            # plotting\n",
    "            if frame_idx % plotting_interval == 0:\n",
    "                self._plot(frame_idx, scores, losses, epsilons)\n",
    "                \n",
    "        self.env.close()\n",
    "                \n",
    "    def test(self, video_folder: str) -> None:\n",
    "        \"\"\"Test the agent.\"\"\"\n",
    "        self.is_test = True\n",
    "        \n",
    "        # for recording a video\n",
    "        naive_env = self.env\n",
    "        self.env = gym.wrappers.RecordVideo(self.env, video_folder=video_folder)\n",
    "        \n",
    "        state, _ = self.env.reset(seed=self.seed)\n",
    "        done = False\n",
    "        score = 0\n",
    "        \n",
    "        while not done:\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "        \n",
    "        print(\"score: \", score)\n",
    "        self.env.close()\n",
    "        \n",
    "        # reset\n",
    "        self.env = naive_env\n",
    "        \n",
    "    def _compute_dqn_loss(\n",
    "        self, \n",
    "        samples: Dict[str, np.ndarray], \n",
    "        gamma: float\n",
    "    ) -> torch.Tensor:\n",
    "        \"\"\"Return dqn loss.\"\"\"\n",
    "        device = self.device  # for shortening the following lines\n",
    "        state = torch.FloatTensor(samples[\"obs\"]).to(device)\n",
    "        next_state = torch.FloatTensor(samples[\"next_obs\"]).to(device)\n",
    "        action = torch.LongTensor(samples[\"acts\"].reshape(-1, 1)).to(device)\n",
    "        reward = torch.FloatTensor(samples[\"rews\"].reshape(-1, 1)).to(device)\n",
    "        done = torch.FloatTensor(samples[\"done\"].reshape(-1, 1)).to(device)\n",
    "\n",
    "        # G_t   = r + gamma * v(s_{t+1})  if state != Terminal\n",
    "        #       = r                       otherwise\n",
    "        curr_q_value = self.dqn(state).gather(1, action)\n",
    "        next_q_value = self.dqn_target(next_state).max(\n",
    "            dim=1, keepdim=True\n",
    "        )[0].detach()\n",
    "        mask = 1 - done\n",
    "        target = (reward + gamma * next_q_value * mask).to(self.device)\n",
    "\n",
    "        # calculate dqn loss\n",
    "        loss = F.smooth_l1_loss(curr_q_value, target)\n",
    "\n",
    "        return loss\n",
    "\n",
    "    def _target_hard_update(self):\n",
    "        \"\"\"Hard update: target <- local.\"\"\"\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "                \n",
    "    def _plot(\n",
    "        self, \n",
    "        frame_idx: int, \n",
    "        scores: List[float], \n",
    "        losses: List[float], \n",
    "        epsilons: List[float],\n",
    "    ):\n",
    "        \"\"\"Plot the training progresses.\"\"\"\n",
    "        clear_output(True)\n",
    "        plt.figure(figsize=(20, 5))\n",
    "        plt.subplot(131)\n",
    "        plt.title('frame %s. score: %s' % (frame_idx, np.mean(scores[-10:])))\n",
    "        plt.plot(scores)\n",
    "        plt.subplot(132)\n",
    "        plt.title('loss')\n",
    "        plt.plot(losses)\n",
    "        plt.subplot(133)\n",
    "        plt.title('epsilons')\n",
    "        plt.plot(epsilons)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment\n",
    "\n",
    "You can see the [code](https://github.com/Farama-Foundation/Gymnasium/blob/main/gymnasium/envs/classic_control/cartpole.py) and [configurations](https://github.com/Farama-Foundation/Gymnasium/blob/main/gymnasium/envs/classic_control/cartpole.py#L91) of CartPole-v1 from Farama Gymnasium's repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# environment\n",
    "env = gym.make(\"CartPole-v1\", max_episode_steps=200, render_mode=\"rgb_array\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set random seed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "seed = 777\n",
    "\n",
    "def seed_torch(seed):\n",
    "    torch.manual_seed(seed)\n",
    "    if torch.backends.cudnn.enabled:\n",
    "        torch.cuda.manual_seed(seed)\n",
    "        torch.backends.cudnn.benchmark = False\n",
    "        torch.backends.cudnn.deterministic = True\n",
    "\n",
    "np.random.seed(seed)\n",
    "seed_torch(seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cpu\n"
     ]
    }
   ],
   "source": [
    "# parameters\n",
    "num_frames = 10000\n",
    "memory_size = 2000\n",
    "batch_size = 32\n",
    "target_update = 100\n",
    "epsilon_decay = 1 / 2000\n",
    "\n",
    "# train\n",
    "agent = DQNAgent(env, memory_size, batch_size, target_update, epsilon_decay, seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 1440x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "agent.train(num_frames)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test\n",
    "\n",
    "Run the trained agent (1 episode)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Moviepy - Building video /Users/jinwoo.park/Repositories/rainbow-is-all-you-need/videos/n_step_learning/rl-video-episode-0.mp4.\n",
      "Moviepy - Writing video /Users/jinwoo.park/Repositories/rainbow-is-all-you-need/videos/n_step_learning/rl-video-episode-0.mp4\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                                                               "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Moviepy - Done !\n",
      "Moviepy - video ready /Users/jinwoo.park/Repositories/rainbow-is-all-you-need/videos/n_step_learning/rl-video-episode-0.mp4\n",
      "score:  200.0\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r"
     ]
    }
   ],
   "source": [
    "video_folder=\"videos/n_step_learning\"\n",
    "agent.test(video_folder=video_folder)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Render"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <video width=\"320\" height=\"240\" alt=\"test\" controls>\n",
       "        <source src=\"data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAJKNtZGF0AAACsAYF//+s3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE2MSByMzAzME0gOGJkNmQyOCAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMjAgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz0xMiBsb29rYWhlYWRfdGhyZWFkcz0yIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MiBrZXlpbnQ9MjUwIGtleWludF9taW49MjUgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIzLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MToxLjAwAIAAAAHFZYiEACv//vZzfAprRzOVLgV292aj5dCS5fsQYPrQAA1PkAAAAwAVOr8dejkBDVIAAAMACxAB0hJQ8g8xExVioEsGkuTgZqMQe55WoWPCuhEc3vWObDHmBb5VOyFz8CVRgeEIHydRykWp5GBQcYPM/AZgsXv/mIv/dBAGGepJvb5F9HBds32AUJPmTQeHZRAtPvUAxJrrT1nENMzSX/OXFC7xhJFNEX9D5hKWGsALdvALhjXM6itwo12VRsqjTEALpvNj+Yvr2Hm/Zo/21NT2EAPbCFKSJQUVueDxfsohlvELjyqbQ1mSljttJLvNgOIC63phcIJsjGk8MhwRVPrIq2nL7fOed6yMdGBjqALvi5lGNjgXfzlylgDkko00XBc/rhyV5uLLfNaKRgXUE62uwIlO2TUoKfCPhNaCHb6mxxuduVCMxMkqXuHDgqTJndEAmkBSENBCYf+kkBenedkuk8vd7fRocUxsjV3N0ZH9CyNv8AxWXXL2tViOhQBe+qOmxT4gAK1kc57dvqYMXl1YNg/g8VPPqpKaNn7zJwy/0glnBPcxrId1GdyqPsvPvDpmZ9fayzVIR2GNQ/2gAAADAAADAEBBAAAANkGaJGxCf/3xAAADAAT4OqoAU5eidWzvLRFHLe7uQU2r5+rAKJaovdcriYz+H3MitB6hGm3QQAAAABNBnkJ4hH8AAAMAAksEELQFQjIJAAAAEgGeYXRH/wAAAwADnxXdfnhkEAAAABABnmNqR/8AAAMAAjwKx725AAAASUGaaEmoQWiZTAhX//44QAABDPrygAz/M3FAJaJ/Zl3Ocwbh/XsdHhx1VsvQGzof3Kvwy0aqHdkDE3AJn2Bl6ryU6qHsuAIwSoEAAAAkQZ6GRREsI/8AABa8Q823FcysmUk/ZPa62rGFOSDaZNAkq5sxAAAAKAGepXRH/wAAI7iv3Ds+zA9VVFM1fYRjSZ9aigR7u5+EWFjqWatg/4EAAAAmAZ6nakf/AAAjscwBk5q99J/kvInv4VP5LHaZGU7QcH4CoI6QSoAAAAAXQZqsSahBbJlMCE///fEAAAMAAAMAHpAAAAAQQZ7KRRUsI/8AAAMAAAMBBwAAAA4Bnul0R/8AAAMAAAMBqQAAAA4BnutqR/8AAAMAAAMBqQAAAExBmvBJqEFsmUwIT//98QAAAwAjmbMNWzF5TQBoKO3DCnCNeCEtrSsWRE5Jfubmy+tHHmkH0koNQnfBcdQkhcfkKPCQJvU2MMgO1gnBAAAAHEGfDkUVLCP/AAADATWBQ2mZfMHFb+nQuAZRbcEAAAAZAZ8tdEf/AAADALp5faKmlVTratx2lOejtwAAAA4Bny9qR/8AAAMAAAMBqQAAAC9BmzRJqEFsmUwIT//98QAAAwKfBR0/YBGXB0pjqD0Zt1PUGxQx6QTtsdFfT+j5gAAAAC5Bn1JFFSwj/wAAFrxDzbcVzYIM1osCm+ADjaxqD38tvNXq1mwxO462KxxWwLtxAAAAGgGfcXRH/wAABPvQwhhtcR6bnr15LR5mlhICAAAAJAGfc2pH/wAAI78EH/4mnCHn8DzOlIh0rMH0UT/+gMOq/eSckAAAAEpBm3hJqEFsmUwIV//+OEAAACbe5AgBwJ1aBmewBW3NygNTSll1n8kNC5CnN+LmwRBvAzAW8qNcywtSAV6DdzIX64wT70xsIJeRwQAAABxBn5ZFFSwj/wAAAwE1gUNpmXzBxW/p0LgGUW3AAAAAHAGftXRH/wAAAwHmsbCUqUTnPOtv8x5GhOyk7cEAAAAOAZ+3akf/AAADAAADAakAAAAZQZu8SahBbJlMCE///fEAAAMAABm6MG41FAAAACJBn9pFFSwj/wAAAwM5fNK6gJMuuFvN0oapDso6cU2CerbhAAAAGgGf+XRH/wAAAwHmsbCUqUTuDbgSXwY9FvwYAAAAJAGf+2pH/wAAI65eM3+wHkMy4MIC3Bt68yGmL44co23IB/MkwQAAAEdBm+BJqEFsmUwIT//98QAAAwKfBWDgjf64iHDAOZ85zVdtc2LECdhTU9V1WRnoX/BxJqyALxacjMfw2IDN/bU6mZx/SOR34QAAAClBnh5FFSwj/wAAFrUrN2txjsdADSn8GnQzc2y/pqV7AsJy9JUaV147ZgAAABgBnj10R/8AACOr+F16cGr+vt0QrcMghYAAAAAbAZ4/akf/AAAFHzTVsZMLz+vAFQ1fzZBFsO3BAAAAN0GaJEmoQWyZTAhX//44QAABDPrfPykQWlGnOFiL5v7SRQNA/nQAsYm2PQST5fbNDJvGc+UafkAAAAAaQZ5CRRUsI/8AABa8Q823FcysmUlDL7RtyBkAAAAOAZ5hdEf/AAADAAADAakAAAAYAZ5jakf/AAAjvwQnEslpmrhWayk0J6bhAAAAF0GaaEmoQWyZTAhP//3xAAADAAADAB6RAAAAEEGehkUVLCP/AAADAAADAQcAAABCAZ6ldEf/AAANepzezXFxAAC6gD9GZpacCoN5tW1D71wpe06tuqj8FNXZuQ9f8mUmr+Gtd0RtC8ejexbWAy3bwfwdAAAADgGep2pH/wAAAwAAAwGpAAAATEGarEmoQWyZTAhP//3xAAADACOZsw1bM7OEADb/uyIfGLD5QEg0lkc/fyeb4TdooZyR9iPCN1vqclv6VJTGvwAOa7KwYo6Cboom/wMAAAA2QZ7KRRUsI/8AAAMDIoZMJDkdUVMwAbfyhMbQxiv6LK0LvH8u2BLJ99glrcu5tjGl498nA7ZhAAAAIgGe6XRH/wAABPvR4kKbq+YIvxsKbthXsTsTwSK3I9LkkmAAAAAbAZ7rakf/AAAE+zTV3tuIaoJIG+jw6CRwkZOSAAAAUkGa8EmoQWyZTAhX//44QAABDPrygAi+tGa3LnIsLlzrE7dEbMF7JarHe1bP7ouDyqK27E5Pfy/ziGDe8E6ns0GRdwUqjqH6ORfEnvxb9+jpfMEAAAAdQZ8ORRUsI/8AABa1KzdrWl64ooPCMLA53Kd5PQUAAAAlAZ8tdEf/AAAjq/hbeBmf213a5L+Mam2a5BKQk0h7+PMRCIP4MQAAAA4Bny9qR/8AAAMAAAMBqQAAACZBmzRJqEFsmUwIT//98QAAAwAAQ0BEQHK32HOx6yfoqZW//e8w8AAAAClBn1JFFSwj/wAAAwMihkgIn7t5mFSpTdiuVhKKkedjZUNtHJxYRvzbMQAAABoBn3F0R/8AAAT70MIYbXEem569eS0eZpYSAgAAABoBn3NqR/8AAAT5PmG3ZGdtFwnJvv7btWpJgAAAADBBm3hJqEFsmUwIR//94QAABBN4JTpUJIV11B+PNRD/lnPEaWpwPN65jP9be9N5KUkAAAA9QZ+WRRUsI/8AABa1KzQ9VAizbgBwJNHEeMLFM4tji31MjLjaYNn1cVkwDrLVeEWZUczbVdhSYMKOIRp24AAAACMBn7V0R/8AACOr+F16b/1UraERqNixtY1S+PYwFQjsdYtICQAAABwBn7dqR/8AAAUfMJZ7iS012m4CSkasGEdmnEVHAAAAOkGbu0moQWyZTAhP//3xAAADAF/8z8H7uXz9PMYtUu0J6K/AC8UHT3ADETl/BkWwRjkQbbzvpX9T/nwAAAAeQZ/ZRRUsI/8AAAMDOFMIqQbcjlvX5iFqD+5oefwZAAAAEAGf+mpH/wAAAwHbf+KAakAAAABCQZv/SahBbJlMCF///oywAABGem9CIcMS5ndUnEMuEClnpnM+/YVXpPQhXvoCOgWxpqeodInotmqR1NkaTHkBUZ5RAAAAHkGeHUUVLCP/AAAWtSs3a1peuKKDwjCwOdzHjAUwrQAAACMBnjx0R/8AACPDF2ippS/2Abuez0GOLv+al0aAp3Ww/2lkwAAAAA4Bnj5qR/8AAAMAAAMBqQAAAEtBmiJJqEFsmUwIV//+OEAAAA4pTP6bbTu+vY6UBJS00NxX+1sJdYADarsX4wrGQEfVrcA2442/PirY5Jxbc9aTZfDriNLDII77JPkAAAAfQZ5ARRUsI/8AAAMBLeTmzC2FJmmb8hIsSEVUic4VgAAAABoBnmFqR/8AAAMB23/VbGss9Jf69+34V9KSYQAAAFJBmmZJqEFsmUwIT//98QAAAwBdGztOABs+NaMVfp9F74QnjptWSOcYfCWYqGAh5/PNfiUKzJM8+kYELNwrdXbzbMZTOBVUIlzbNBh0G0Db5hKwAAAALEGehEUVLCP/AAADAx6j3I04AIJ4qnSB0epgpBvcZWT+djs41psjT/5NCsJ9AAAAHAGeo3RH/wAABPhbeZLHx+T0txvbKnRXrE7P+UEAAAATAZ6lakf/AAADABnJIZuKqluPgQAAADhBmqpJqEFsmUwIR//94QAAAwP1YSseAHQM6up1PBfR314cejYRYQEcORrZ9t8RQKW/Gjd6Koc5hwAAABdBnshFFSwj/wAAFiVYVYrOP9if9ZfDrgAAABYBnud0R/8AACKsOQWuTx8/FWhkoHXAAAAADgGe6WpH/wAAAwAAAwGpAAAAiEGa7UmoQWyZTAhX//44QAABBU8wLvAtFXtnWTjoqfxAFf69V7rvB5A0MvgSy1PI3XW/sjJqvIe8Vm1n7rDuyjw7P9dOMQnErABuCn1LhoIJlEjbC4jocHvp4gS1JF3Yj6wMSzNAxyltwyCV9NZRZZ18nKqUCa+YwdJby4pe98iFa0oqj1CA/BAAAAAeQZ8LRRUsI/8AABYsTmzC2EsLSp4072FjYY8fthPgAAAAHgGfLGpH/wAAIrIrBxErn+3lSo3OTpM+TaVjqLjsfQAAADJBmzFJqEFsmUwIT//98QAAAwAi3TJgBQBDByFTQW6Vhl2XaKepobLCHAjcaOlyNJHCXwAAAEZBn09FFSwj/wAAAwMiaPdgAtbRoefalTjhUTbDV6SLT37tYhfX4KgLXYw47Vhfk0A5AeMXZwPuxsON7lTU2S69K9MJ+ICBAAAAGwGfbnRH/wAABPhXHbOk8AAGKhfcsyAqqpTHJAAAABsBn3BqR/8AAAT5MAjLrt8jMK2rJ+pbMCxdICAAAABcQZt1SahBbJlMCFf//jhAAAEE+vKACL66ISPGh17fhTwH4yQvZupDXz9vQS0sOoFPu4Fbpaj+vs2YuOfFnhcm0uABJe8jzf5xVwIYhAPC1UWWX5H/ymiVLdD5TpUAAAAkQZ+TRRUsI/8AABYlWFXlkytEqMwwCKV8Hw0widhE/EXXCrcWAAAAGAGfsnRH/wAAIsM+Dnh27S223M+fPZDPgAAAAB8Bn7RqR/8AAA0Ojgj6g6gPZblEkqSw9N349MbtqobBAAAAIUGbuUmoQWyZTAhP//3xAAADAF/9N19XkM+lpZuRCYD5gAAAABdBn9dFFSwj/wAAAwE1gVQ4xOqyWDSkgQAAABQBn/Z0R/8AAAMB5Yoet9kvSasyLwAAACwBn/hqR/8AAAMAumQLkIAR5HTFeETcuudSM7PpnBU+NEVkBqgA0EqIRayflAAAAD1Bm/1JqEFsmUwIR//94QAAAwP1YSseACF7AD0tw3G5DgFLjwAxEezFsIOSrMKsdvpTq9oOH1yu/OchS16hAAAAHkGeG0UVLCP/AAAWJVhVis7yIypKuFoDK/jKjegTcAAAACMBnjp0R/8AACLDMvx++7fZcJYeSt5y5hJYK2eQFNvs0yJDwQAAABABnjxqR/8AAAMAumahQIeBAAAAN0GaIUmoQWyZTAhP//3xAAADAA0+ikz8aa3WAGu4z51SNWYFUA0RNy1gT8VEqijFIJa8syAjBYAAAAA1QZ5fRRUsI/8AABYjSIvfG5Gda2ADjaxldqqo5MbLkU0QXozcxcVtHbuhtc3bToWYgq7QoVsAAAAYAZ5+dEf/AAAiwz4MG2d2G4UICApn+LaBAAAAHQGeYGpH/wAAIr8aznveIBEI8MMCpdE4bPGlxibgAAAAWkGaYkmoQWyZTAhP//3xAAADAPP/JUgBagAB6PqLwaZxuJqWCYPraaQmPfoxFNvhrE0tkhgKF1eGfO9AAQAOMBSK/uOz9owvrfLqEQFq2qOZTZ4Q0/B0TmNXoQAAAFZBmoZJ4QpSZTAhP/3xAAADAo30lEB75w1zaRLGvk4djppApdHWrK3n6N2iXbvYBPZg75o5aaF67eSbRxHWPPm4qO3DeJxSouSN+H71WcWLAG10TbL33gAAAExBnqRFNEwj/wAAFixLc+mQgBWL9orLCzGgFo5LxNiX+gqVc25NliWdgVBpVAgbplLQLPwY4dXOjXYG+4c86V3hNm9sg7EHSMgyMXixAAAAHAGew3RH/wAAIcNCacCKqaRd1DpClpQGN6z78J8AAAAZAZ7Fakf/AAAiscwJb6lvs7NNf6OJToBSQQAAADBBmspJqEFomUwIV//+OEAAAQU4iGxQX/WkfYVM125PPY0dInK8CZKTngEA7/e85E0AAAAaQZ7oRREsI/8AABYsQ823FcysmZCd+IVwQ8AAAAAQAZ8HdEf/AAADALoLfsCrgAAAABkBnwlqR/8AACKxzAlvqW+zs02AEQTJpxtRAAAAOEGbDkmoQWyZTAhP//3xAAADAFqYmRrp1VP1l+wlkl0LNFIFAAZPrmUKpP+TyGBTeSYY2HFVrCTaAAAAH0GfLEUVLCP/AAADASYloWCZRTGaaRKLiEuhYEGDfJsAAAAdAZ9LdEf/AAADAdCyLd9Ka1p9rHJQZr0El2npcm0AAAAQAZ9Nakf/AAADALpmoUCHgQAAADdBm1JJqEFsmUwIV//+OEAAAQWVbF3uYCHqS3P7K0/ffuQ9K6t41/Chae7MyYai5q6bVTMu2ythAAAAG0GfcEUVLCP/AAAWJSs3a1peuO5xqgiU8EFxSQAAABgBn490R/8AACLDF2ippVPVFinEaLCpAnYAAAAnAZ+Rakf/AAAE90vIni7VpJHykjWpr0oakxMyMg4c/1lydhPcd8WBAAAAQUGblkmoQWyZTAhP//3xAAADACGZs0JW6/64kocVnv61YAijz0AQvjj77ytKUnrOihRb1dothsSWlegfPEbYbCsgAAAAH0GftEUVLCP/AAADASXlDcTr5EeuX8HiuM4p2dv5qQsAAAASAZ/TdEf/AAADALoLiRdvwJuBAAAAHAGf1WpH/wAAAwHQgBdgK5UtgeO/v3HQSOEjJ0wAAAA7QZvaSahBbJlMCE///fEAAAMCjrUM+gkJbDWAYjAQR0CZH0JaeuX1W/7/KSBnBD7w/iZ0qbB/oB62RbUAAAAlQZ/4RRUsI/8AABYlKzfSUAJHkfTfVl6BrWlIYVauOf2TIMb9EwAAAB4Bnhd0R/8AACKr+FtdV5jhI6y9eIWHp+jahGVgjZgAAAAYAZ4Zakf/AAAMvo3/zF6JS+S+hXZh3QqZAAAANkGaHkmoQWyZTAhP//3xAAADAo3t9/4rIh+z6Edwu1RPLDT/RI2dtgBCJ+lwC7Ad5BxJ9VpUDAAAACJBnjxFFSwj/wAAFixDzbxFACR8wHDADWaHmM9tqnZCshUxAAAAFAGeW3RH/wAADN4S8yV0d47B6tETAAAAFwGeXWpH/wAAIrHMCW+N7hyM1wodMMuAAAAAQUGaQkmoQWyZTAhP//3xAAADAF19OhrJt6rJ47YsnQNeuAe9hLvUpgDusEj8ah582n3fd9WzWMbkq6PtNkkznsnoAAAAHEGeYEUVLCP/AAADAyRTCrDhfnRLYC6n65oxp4MAAAAZAZ6fdEf/AAAE+9DBzxq47mziEiU+LHd+LAAAAA4BnoFqR/8AAAMAAAMBqQAAAEBBmoZJqEFsmUwIV//+OEAAAQT68oANRqXDt94F4UvK9ADYbeajUkoGor2MMkrSBbJs41RjP3APSJazsq2Yo6+uAAAAIkGepEUVLCP/AAAWLEPNtxXNggzWi0WD4knyHOxLaUHoKrEAAAAaAZ7DdEf/AAAE2GfCGG1xHpuevXktHmaWEhcAAAAWAZ7Fakf/AAAiscwJb6lvshVShawTcQAAAD1BmspJqEFsmUwIT//98QAAAwAhmbNCVwoGrWyhABcOTtl23XPgYSiPZpbMs84s1OKLiH0kUSmH5p2JeRbBAAAAHUGe6EUVLCP/AAADAw+uhC9eCVJkHQxZBP76F2IWAAAAGgGfB3RH/wAABNhnwhhtcR6bnr15LR5mlhIWAAAAIwGfCWpH/wAAAwAJ+QiR6B/jwcmAA96WPcWPQkhCChfjD3ypAAAAM0GbDkmoQWyZTAhX//44QAABBPrgn68BXZJu+CIXYye9hI+smOfHWEnSbR5IPAKcW9iI2AAAAC5BnyxFFSwj/wAAFiUrN2thKX3Y8kRBsAG0eOZyizs2gYXOevYRjuYXlsAwMXcEAAAAHQGfS3RH/wAAIsMXaKmleTxG6uiOrcgcpFjc6wQtAAAAGwGfTWpH/wAAAwC15hLPdmzvrWvNG67A1rW3oQAAADRBm1JJqEFsmUwIT//98QAAAwAhmbNAcQ5ee5+W6cDzY4C7Cyk8Zc4EAw+hifySZyam3DapAAAAH0GfcEUVLCP/AAADASXlC29NRkTLBQAw9ElJ3h3SXJsAAAAQAZ+PdEf/AAADABm8J9iZgAAAABwBn5FqR/8AAAMB0IAS+OBpuK11QpcJO2ZW4OmBAAAAPUGblkmoQWyZTAhP//3xAAADAo0FYOBTDGuPsC4yXKnSY/ehB7SRHOfyaqvUjC/n5vY8Xc8A/SEg83BApIAAAAAeQZ+0RRUsI/8AABYlKzdttoAS2qwF95umLd9wrQz4AAAAFwGf03RH/wAAIqv4W3gSnWgjiCXHnx0DAAAADgGf1WpH/wAAAwAAAwGpAAAAQ0Gb2kmoQWyZTAhP//3xAAADAo3t9/6uoQOUoUAa50IJfZVWtWyL9nTIBMvvrDonWQVqdHS0sEQiD3135ytV5GnthxUAAAAZQZ/4RRUsI/8AABYlKzdrWl64o31KnWwy4QAAABcBnhd0R/8AACLDF2ippVPU+8aF6VyN6AAAABABnhlqR/8AAAMAsXaAygR9AAAAWEGaHkmoQWyZTAhP//3xAAADAntCYBQ92zXtWy6qog3rWvK5n6+pTdY2lLBwkpt66kHarJRMPi0PJLn9IOa7mk86cy2idHD3gbkWvlcVftGwL/bjnATp+zgAAAAiQZ48RRUsI/8AAAMDG+5BBHhVqm5bkESyCBAybs+JwpLb0QAAABsBnlt0R/8AAAT70JgJk2y3p80U6iTLJ9Q2LxcAAAATAZ5dakf/AAAE+zTVsaywKTQ3oAAAAEFBmkJJqEFsmUwIV//+OEAAAQT68oAIvrRmty5yLA8woHj5niNVhUlluJOcv//uGTj3R33qkLCgnLlKB0V+glg/vAAAAB1BnmBFFSwj/wAAFiUrN2taXriig8IwsDncx5qHTQAAACMBnp90R/8AACLDF2ipnfHJuOswiOp2DJY63Y1emIi7ASnkLAAAAA4BnoFqR/8AAAMAAAMBqQAAAC5BmoZJqEFsmUwIT//98QAAAwAhs/314L4mbWUwHaRmuUgwKqpxgqSjLHU5zZ4YAAAAHkGepEUVLCP/AAADASXlC29NRkS7BHBPVLXzC4aQsQAAAA4BnsN0R/8AAAMAAAMBqQAAABwBnsVqR/8AAAMB0IAS+OBpuK11QpcJO2ZW4OmBAAAAK0GaykmoQWyZTAhP//3xAAADAo0FDwScBREu5YZi3sK0fkGEWxDw9VyhQu8AAAAeQZ7oRRUsI/8AABYlKzdrWnT0ALF5nJ4yxGkkFFtAAAAAFwGfB3RH/wAAIqv4W3gSnWgjiCXIlh9wAAAAEAGfCWpH/wAAAwHQf+KAbMEAAABNQZsOSahBbJlMCE///fEAAAMCkew4NTIKxOBT9K099XGMCipyDQQo0eJOrcAjvIeDLHJeCyJ/3fVziOLhnZe+mmSDiUcpnoXo0gtdQvYAAAAbQZ8sRRUsI/8AABYsQ823FcyspTrq8n7jt1BAAAAAEAGfS3RH/wAAAwHPij2AhYEAAAAXAZ9Nakf/AAAiscwJb6lvshWXVdltbMEAAABFQZtSSahBbJlMCE///fEAAAMA8/utazVmAXLwGY1t2b44TWeoxcTn1MAMOTro7FDRgJ27dapuupTkZAwi5AMb1VlT3NApAAAAHEGfcEUVLCP/AAAILAoeRWXeTqhmDQyFkCNZJsAAAAAaAZ+PdEf/AAANNeuHjGrjuZU2qEBSvP5oCFgAAAAOAZ+Rakf/AAADAAADAakAAAA5QZuWSahBbJlMCFf//jhAAAD9aUrvjlAAFtKr0q47gALbuImZQYEhltL97wsSI2VX5qXolWQJ/Da2AAAAG0GftEUVLCP/AAAVlVhVis4/2KEZFabd3LwHvQAAACEBn9N0R/8AACGsOQVsGtdGeLUE4dTYF9z18+h3qngZKfEAAAAOAZ/Vakf/AAADAAADAakAAABAQZvaSahBbJlMCE///fEAAAMAIbP945NA+ACH1F2xyScMsOJrIABAFR39bTf4LPd9QVeMYR2xS8NnnTaLZAbJqQAAACBBn/hFFSwj/wAAAwElgPGpBQEl0LTAB5K1wpi0FWWUgQAAABoBnhd0R/8AAAMB0LGw8Y2QiRUWvMhF2QZlIAAAAA4BnhlqR/8AAAMAAAMBqQAAACpBmh5JqEFsmUwIV//+OEAAAP1pSu+LdvUNdSYR/AJhGwwoKHgGXzLn2ygAAAAXQZ48RRUsI/8AABWVWFWKzj/Y2J1Dx3UAAAAUAZ5bdEf/AAAhrDkFrk8fPxV/hl0AAAAQAZ5dakf/AAADABkpPCh8wAAAAEZBmkFJqEFsmUwIT//98QAAAwAhs/3bMqqzGrqPp6gAsAa0WKuvQDqT9AMiPkOq3vznibl7UtwXmUj8fEndNCuWxNJYrW7gAAAANEGef0UVLCP/AAAVk0iL4kwANMYWQ3ORmVnxZTas71LY6FqQ4kIi6gtMiRGZujF6L65K8RcAAAAhAZ6Aakf/AAAhvxrOe94gMLN6+OTWGFh7F2w53qZWEuXHAAAAM0GahUmoQWyZTAhP//3xAAADAnvKUszhZKkBmZnN6At7seM/wPLyhJmaCbwk+3/vR2gBGwAAAClBnqNFFSwj/wAAFZVYVR8wWxYMjWEH03NLMcKRK4XlpKzv/sUFqDmKkAAAADABnsJ0R/8AACHDOmdlfWUEABc9XXPtKIqIZuJWA4mDUrGNU4Wl2VHf77lMOwkWs+EAAAAfAZ7Eakf/AAAE0lerh5pnfYE3bfmSCa70ltMhUOOZgQAAAEJBmslJqEFsmUwI//yEAAAPI+bXtQ9QAAlqNp2imPr8Kzd5w1w8Sylf+yuDnocDCL1LH/JM55Gds5hel1gsoI6fFiEAAAAvQZ7nRRUsI/8AABWTLIcoTys8E6+cxHzVlhsXxDUvpokuHvKAEn5Ji0s3Ik81Z8EAAAAvAZ8GdEf/AAAhrDkFfjUwFQAturqfMcr+j13jsuIJRG6gpAtpo908fW3WgXTq7PgAAAAdAZ8Iakf/AAAhsiZWHU9W4QM7QI+ya64Kcxhya7gAAAyDbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAD8gAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAC610cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAD8gAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAlgAAAGQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAA/IAAACAAABAAAAAAslbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAyAAAAygBVxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAAK0G1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAACpBzdGJsAAAAsHN0c2QAAAAAAAAAAQAAAKBhdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAlgBkABIAAAASAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGP//AAAANmF2Y0MBZAAf/+EAGWdkAB+s2UCYM+XhAAADAAEAAAMAZA8YMZYBAAZo6+PLIsD9+PgAAAAAFGJ0cnQAAAAAAABIfAAASHwAAAAYc3R0cwAAAAAAAAABAAAAygAAAQAAAAAUc3RzcwAAAAAAAAABAAAAAQAABkBjdHRzAAAAAAAAAMYAAAABAAACAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAEAAAAAAIAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAEAAAAAAIAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAQAAAAAAgAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAAAgAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAABAAAFAAAAAAEAAAIAAAAAAQAAAAAAAAABAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABAAAAAACAAABAAAAAAEAAAUAAAAAAQAAAgAAAAABAAAAAAAAAAEAAAEAAAAAAQAABQAAAAABAAACAAAAAAEAAAAAAAAAAQAAAQAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAMoAAAABAAADPHN0c3oAAAAAAAAAAAAAAMoAAAR9AAAAOgAAABcAAAAWAAAAFAAAAE0AAAAoAAAALAAAACoAAAAbAAAAFAAAABIAAAASAAAAUAAAACAAAAAdAAAAEgAAADMAAAAyAAAAHgAAACgAAABOAAAAIAAAACAAAAASAAAAHQAAACYAAAAeAAAAKAAAAEsAAAAtAAAAHAAAAB8AAAA7AAAAHgAAABIAAAAcAAAAGwAAABQAAABGAAAAEgAAAFAAAAA6AAAAJgAAAB8AAABWAAAAIQAAACkAAAASAAAAKgAAAC0AAAAeAAAAHgAAADQAAABBAAAAJwAAACAAAAA+AAAAIgAAABQAAABGAAAAIgAAACcAAAASAAAATwAAACMAAAAeAAAAVgAAADAAAAAgAAAAFwAAADwAAAAbAAAAGgAAABIAAACMAAAAIgAAACIAAAA2AAAASgAAAB8AAAAfAAAAYAAAACgAAAAcAAAAIwAAACUAAAAbAAAAGAAAADAAAABBAAAAIgAAACcAAAAUAAAAOwAAADkAAAAcAAAAIQAAAF4AAABaAAAAUAAAACAAAAAdAAAANAAAAB4AAAAUAAAAHQAAADwAAAAjAAAAIQAAABQAAAA7AAAAHwAAABwAAAArAAAARQAAACMAAAAWAAAAIAAAAD8AAAApAAAAIgAAABwAAAA6AAAAJgAAABgAAAAbAAAARQAAACAAAAAdAAAAEgAAAEQAAAAmAAAAHgAAABoAAABBAAAAIQAAAB4AAAAnAAAANwAAADIAAAAhAAAAHwAAADgAAAAjAAAAFAAAACAAAABBAAAAIgAAABsAAAASAAAARwAAAB0AAAAbAAAAFAAAAFwAAAAmAAAAHwAAABcAAABFAAAAIQAAACcAAAASAAAAMgAAACIAAAASAAAAIAAAAC8AAAAiAAAAGwAAABQAAABRAAAAHwAAABQAAAAbAAAASQAAACAAAAAeAAAAEgAAAD0AAAAfAAAAJQAAABIAAABEAAAAJAAAAB4AAAASAAAALgAAABsAAAAYAAAAFAAAAEoAAAA4AAAAJQAAADcAAAAtAAAANAAAACMAAABGAAAAMwAAADMAAAAhAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjU4Ljc2LjEwMA==\" type=\"video/mp4\"/>\n",
       "        </video>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Played: videos/n_step_learning/rl-video-episode-0.mp4\n"
     ]
    }
   ],
   "source": [
    "import base64\n",
    "import glob\n",
    "import io\n",
    "import os\n",
    "\n",
    "from IPython.display import HTML, display\n",
    "\n",
    "\n",
    "def ipython_show_video(path: str) -> None:\n",
    "    \"\"\"Show a video at `path` within IPython Notebook.\"\"\"\n",
    "    if not os.path.isfile(path):\n",
    "        raise NameError(\"Cannot access: {}\".format(path))\n",
    "\n",
    "    video = io.open(path, \"r+b\").read()\n",
    "    encoded = base64.b64encode(video)\n",
    "\n",
    "    display(HTML(\n",
    "        data=\"\"\"\n",
    "        <video width=\"320\" height=\"240\" alt=\"test\" controls>\n",
    "        <source src=\"data:video/mp4;base64,{0}\" type=\"video/mp4\"/>\n",
    "        </video>\n",
    "        \"\"\".format(encoded.decode(\"ascii\"))\n",
    "    ))\n",
    "\n",
    "\n",
    "def show_latest_video(video_folder: str) -> str:\n",
    "    \"\"\"Show the most recently recorded video from video folder.\"\"\"\n",
    "    list_of_files = glob.glob(os.path.join(video_folder, \"*.mp4\"))\n",
    "    latest_file = max(list_of_files, key=os.path.getctime)\n",
    "    ipython_show_video(latest_file)\n",
    "    return latest_file\n",
    "\n",
    "\n",
    "latest_file = show_latest_video(video_folder=video_folder)\n",
    "print(\"Played:\", latest_file)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "rainbow-is-all-you-need",
   "language": "python",
   "name": "rainbow-is-all-you-need"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
